/**
 * \file
 */

#ifndef NODE_H
#define NODE_H

#include "uthash.h"
#include "plist.h"

/*! @file node.h
 *  @brief < Estructura y funciones del nodo >
 */
 
/*! @struct s_node 
 *  @brief Esta estructura representa un nodo.
 *  @param name Nombre del nodo
 *  @param visited Indica si el nodo fue visitado
 *  @param level < Falta aclarar >
 *  @param neigbours Lista de vecinos del nodo
 *  @param neighbours_count Cantidad de vecinos del nodo
 *  @param hh Hace esta estructura hasheable   
 */
struct s_node{
	unsigned int name;
	bool visited;
    int level;
	plist_t neighbours;
	int neighbours_count;
	UT_hash_handle hh;
};

/*Esta estructura es necesaria aca porque es hasheable y sino el 
     network no acceder.*/

/*! @var typedef struct s_node *node
 *  @brief La estructura s_node la llamaremos con el puntero node. 
 */  
typedef struct s_node *node;

/*! @fn node_create(unsigned int name)
 *  @brief Crea un nodo nuevo.
 *  @param name El 'nombre' del nodo.
 *  @return El nuevo nodo con el nombre 'name'.
 */
node node_create(unsigned int name);

/*! @fn node_visited(node nd)
 *  @brief Verifica si un nodo fue visitado o no.
 *  @param nd El nodo a verificar.
 *  @return True o False segun el nodo fue o no visitado.
 */
bool node_visited(node nd);

/*! @fn node_neighbours(node nd)
 *  @brief Devuelve una lista con todos los vecinos del nodo.
 *  @pre <code> (nd != NULL) </code>
 *  @param nd El nodo a quien se pediran los vecinos.
 *  @return La lista de vecinos del nodo.
 */
plist_t node_neighbours(node nd);

/*! @fn node_destroy(node nd)
 *  @brief Destruye el nodo.
 *  @pre <code> (nd != NULL) </code>
 *  @param nd Nodo a ser destruido.
 *  @return Null.
 */
node node_destroy(node nd);

/*! @fn node_get_level(node nd)
 *  @brief Devuelve el nivel al que se encuentra el nodo.
 *  @pre <code> (nd != NULL) </code>
 *  @param nd El nodo a verificar.
 *  @return Un entero representando el nivel del nodo.
 */
int node_get_level(node nd);


/*! @fn node_set_level(node nd, int level);
 *  @brief Seteamos el nivel del nodo.
 *  @pre <code> (nd != NULL) </code>
 *  @param nd Nodo a setear.
 *  @param level Nivel al que setearemos el nodo.
 */
void node_set_level(node nd, int level);

/*! @fn node_visit(node nd)
 *  @brief Marca como visitado el nodo.
 *  @pre <code> (nd != NULL) </code>
 *  @param nd Nodo a visitar.
 */
void node_visit(node nd);


/*! @fn node_unvisit(node nd)
 *  @brief Marca como no visitado el nodo.
 *  @pre <code> (nd != NULL) </code>
 *  @param nd Nodo a des-visitar.
 */
void node_unvisit(node nd);


/*! @fn node_name(node nd)
 *  @brief Retorna el nombre del nodo.
 *  @pre <code> (nd != NULL) </code>
 *  @param nd Nombre del cual queremos saber el nombre.
 *  @return Un entero con el nombre del nodo.
 */
unsigned int node_name(node nd);

/*! @fn node_add_neighbour(node nd, node to, unsigned int capacity,
                             unsigned int flow, int level, bool backward)
 *  @brief Agrega un vecino a la lista de vecinos del nodo.
 *  @pre <code> (nd != NULL) </code>
 *  @pre <code> (to != NULL) </code>
 *  @param nd Nodo a quien agregaremos el vecino.
 *  @param to El vecino a ser agregado.
 *  @param capacity La capacidad de flujo entre el nodo y su nuevo vecino.
 *  @param flow El flujo que se dirige al nuevo vecino.
 *  @param level El nivel al que se encuentra el vecino.
 *  @param backward True o False dependiendo si se agrega bwd o fwd.
 */
void node_add_neighbour(node nd, node to, unsigned int capacity,
                             unsigned int flow, int level, bool backward);

/*! @fn node_neighbours_fordward(node nd)
 *  @brief Indica si hay vecinos entre los vecinos del nodo nd
 *  @pre <code> (nd != NULL) </code>
 *  @param nd El nodo en cuestion. 
 *  @return True si hay un nodo vecino.
 */
bool node_neighbours_fordward(node nd);

/*! @fn node_delete_neighbour(node nd, unsigned int name)
 *  @brief Borro el vecino name de la lista de vecinos del nodo.
 *  @pre <code> (nd != NULL) </code>
 *  @param nd   El nodo del cual quiero borrar uno de sus vecinos.
 *  @param name El nombre del nodo que quiero borrar.
 */
void node_delete_neighbour(node nd, unsigned int name);

/*! @fn node_get_neighbour(node nd)
 *  @brief Devuelve el primer nodo que este en los vecinos de nd.
 *  @pre <code> (nd != NULL) </code>
 *  @param nd Un nodo al cual se pedira el vecino.
 *  @return Retorna el proximo vecino en la lista de vecinos.
 */
node node_get_neighbour(node nd);

#endif
